package short

import (
	"math/rand"
)

type Logic struct {
	Chars []rune // 字符集
	// 校验码
	CheckSumBase int64 // 底数/进制，将数值转换成CheckSumBase进制的数，将各位上的数字相加，用CheckSumLimit取余，作为校验位，再将值转换成CheckSumLimit进制，在最后添加校验位
	CheckSumLimit int64 // (取不到的)上限，为0时不进行校验
	// 混淆，头部加一个固定位数的随机数再加固定的常数
	ObscureConstant int64 // 常数，可以防止产生过短的字符串，但不要比能生成的随机数更长
	ObscureBase     int64 // 底数/进制，将数值转换为ObscureBase进制的数，在前面添加ObscureDigit位随机数
	ObscureDigit    int   // 前部的随机数的位数，为0时不添加随机数
}

func (l *Logic) SetCharsString(str string) {
	l.Chars = make([]rune, 0)
	for _, char := range str {
		l.Chars = append(l.Chars, char)
	}
}

// 编码
func (l Logic) Encode(num int64) string {
	base := int64(len(l.Chars))
	list := make([]rune, 0)
	for num > 0 {
		list = append([]rune{l.Chars[num % base]}, list...)
		num = num / base
	}
	return string(list)
}

// 解码
func (l Logic) Decode(code string) int64 {
	base := int64(len(l.Chars))
	_map := make(map[rune]int64)
	for i, c := range l.Chars {
		_map[c] = int64(i)
	}
	list := []rune(code)
	var num int64
	for _, c := range list {
		num = num * base + _map[c]
	}
	return num
}

// 计算校验码
func (l Logic) Sum(num int64) (sum int64) {
	for num > 0 {
		sum += num % l.CheckSumBase
		num = num / l.CheckSumBase
	}
	return sum % l.CheckSumLimit
}

// 混淆
func (l Logic) Obscure(num int64) int64 {
	if l.ObscureDigit == 0 {
		return num
	}
	min := GetLimit(l.ObscureDigit-1, l.ObscureBase)
	limit := GetLimit(l.ObscureDigit, l.ObscureBase)
	r := rand.Int63n(limit-min) + min // 随机数:[min, limit)
	u := GetLimit(GetFigure(num, l.ObscureBase)+1, l.ObscureBase) // 单位量
	return num +  r*u + l.ObscureConstant
}

// 反混淆
func (l Logic)UnObscure(num int64) int64 {
	if l.ObscureDigit == 0 {
		return num
	}
	num -= l.ObscureConstant
	return num % GetLimit(GetFigure(num, l.ObscureBase)-l.ObscureDigit, l.ObscureBase)
}

// 加校验
func (l Logic) AppendCheckSum(num int64) int64 {
	if l.CheckSumLimit == 0 {
		return num
	}
	return num * inst.CheckSumLimit + inst.Sum(num)
}

func (l Logic) RemoveCheckSum(num int64) (int64, bool) {
	if l.CheckSumLimit == 0 {
		return num, true
	}
	q := num / inst.CheckSumLimit // 去掉校验值
	return q, inst.Sum(q) == num % inst.CheckSumLimit
}

// 求位数
// base 进制
func GetFigure(num, base int64) int {
	var res int
	for num > 0 {
		res ++
		num = num / base
	}
	return res
}

// 求指定位数的上限(可能的最大值加一)
func GetLimit(f int, base int64) int64 {
	var res int64 = 1
	for i := 0; i < f; i ++ {
		res *= base
	}
	return res
}
